﻿using System.Collections.Generic;
using System.Linq;
using PSE.Deployment.Engine.Interfaces;
using PSE.Deployment.SetupBase.Configuration;
using PSE.Deployment.SetupBase.Steps;
using PSE.Deployment.SetupBase.Parameter.Enums;
using PSE.Deployment.Util;
using PSE.Deployment.Engine.CustomEventArgs;

namespace PSE.Deployment.SetupBase.Groups
{
    public class SetupRepair : SetupExecutionGroup
    {
        private List<Group> _groupsCloned;

        public SetupRepair(IStepGroup parent)
            : base(parent)
        {
            this.Id = "SetupRepair";
        }

        protected override void AddStepsExecution()
        {
            base.AddStepsExecution();

            AddSteps(SetupMode.Uninstall);

            if (this.Steps.Count > 0)
            {
                this.Steps[this.Steps.Count - 1].ExecutionFinished += new System.EventHandler<ExecutionFinishedEventArgs>(SetupRepair_ExecutionFinished);
            }

            AddSteps(SetupMode.Install);

            SetupMainFactory.GetInstance().Parameter.SetupMode = SetupMode.Repair;
        }

        private void AddSteps(SetupMode setupMode)
        {
            List<Group> installedGroups;

            //Altera dos grupos instalados para não instalados
            if (setupMode == SetupMode.Install)
            {
                _groupsCloned = (List<Group>)CloneHelper.Clone(SetupMainFactory.GetInstance().OriginalConfiguration.SystemInfo.Groups);

                installedGroups = SetupMainFactory.GetInstance().OriginalConfiguration.SystemInfo.Groups.
                    SelectDeep(g => g.SubGroups).SelectDeep(g => g.Dependencies).Where(g => (g.Install == null || g.Install.GetValueOrDefault()) && g.Installed).Distinct(new GroupComparer()).ToList();

                installedGroups.ForEach(g => { g.Install = true; g.Installed = false; });

                SetupMainFactory.GetInstance().Parameter.SetupConfiguration = SetupMainFactory.GetInstance().OriginalConfiguration;
            }
            else if (setupMode == SetupMode.Uninstall)
            {
                //Seleciona todos os grupos instalados
                installedGroups = SetupMainFactory.GetInstance().Parameter.SetupConfiguration.SystemInfo.Groups.
                    SelectDeep(g => g.SubGroups).SelectDeep(g => g.Dependencies).Where(g => (g.Install == null || g.Install.GetValueOrDefault()) && g.Installed).Distinct(new GroupComparer()).ToList();

                installedGroups.ForEach(g => { g.Install = false; g.Installed = true; });
            }

            //Altera o modo de instalação de Install
            SetupMainFactory.GetInstance().Parameter.SetupMode = setupMode;

            SetupInstall setupUninstall = new SetupInstall(this);

            foreach (IStep step in setupUninstall.Steps)
            {
                bool addGroup = true;

                if (addGroup)
                {
                    step.Id = setupMode.ToString() + "-" + step.Id;
                    step.Parent = this;
                    this.Steps.Add(step);
                }
            }            
        }

        private void SetupRepair_ExecutionFinished(object sender, ExecutionFinishedEventArgs e)
        {
            List<Group> installedGroups = _groupsCloned.SelectDeep(g => g.SubGroups).SelectDeep(g => g.Dependencies).Where(g => (g.Install == null || g.Install.GetValueOrDefault()) && g.Installed).Distinct(new GroupComparer()).ToList();

            foreach (IStep step in Steps.Where(s => s.Id.StartsWith("Install")))
            {
                SetupGroup setupGroup = step as SetupGroup;

                if (setupGroup != null)
                {
                    Group group = installedGroups.Find(g => g.Id == setupGroup.Group.Id);

                    if (group != null)
                    {
                        setupGroup.Group.Install = group.Install;
                    }
                }
            }
        }
    }
}
